{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 3 More Namespace Operations "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.1 `locals()` and `globals()`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "之前讨论的名字绑定包括如下操作符\n",
    "\n",
    "  - *name* `=` (assignment)\n",
    "  - `del` *name* (unbinds the name)\n",
    "  - `def` *name* function definition (including lambdas)\n",
    "  - `def name(`*names*`):` (function execution)\n",
    "  - *name*`.`*attribute_name* `=`, `__setattr__`, `__delattr__`\n",
    "  - `global`, `nonlocal` (changes scope rules)\n",
    "  - `except Exception as` *name*:\n",
    "  \n",
    "下面我们来探讨一下局部和全局的区别"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'__name__': '__main__',\n",
       " '__doc__': 'Automatically created module for IPython interactive environment',\n",
       " '__package__': None,\n",
       " '__loader__': None,\n",
       " '__spec__': None,\n",
       " '__builtin__': <module 'builtins' (built-in)>,\n",
       " '__builtins__': <module 'builtins' (built-in)>,\n",
       " '_ih': ['', 'locals()'],\n",
       " '_oh': {},\n",
       " '_dh': ['C:\\\\Users\\\\admin\\\\Documents\\\\教案 Jupyter Notebook\\\\jupyter\\\\Python_Epiphanies'],\n",
       " 'In': ['', 'locals()'],\n",
       " 'Out': {},\n",
       " 'get_ipython': <bound method InteractiveShell.get_ipython of <ipykernel.zmqshell.ZMQInteractiveShell object at 0x00000241E7298828>>,\n",
       " 'exit': <IPython.core.autocall.ZMQExitAutocall at 0x241e72fa940>,\n",
       " 'quit': <IPython.core.autocall.ZMQExitAutocall at 0x241e72fa940>,\n",
       " '_': '',\n",
       " '__': '',\n",
       " '___': '',\n",
       " '_i': '',\n",
       " '_ii': '',\n",
       " '_iii': '',\n",
       " '_i1': 'locals()'}"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "locals()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "len(locals())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  In the REPL these are the same:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "locals() == globals()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  The following code is not recommended."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "locals()['x']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "locals()['x'] = 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "locals()['x']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  If you're tempted to use it, try this code which due to \"fast\n",
    "locals\" doesn't do what you might expect:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def f():\n",
    "    locals()['x'] = 5\n",
    "    print(x)\n",
    "f()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.2 The `import` Statement\n",
    "\n",
    "Remember, these change or modify a namespace:\n",
    "\n",
    "- Simple assignment (=) and del\n",
    "- globals() and locals()\n",
    "- import\n",
    "- def\n",
    "- class\n",
    "[Also function parameters, for, except, with, and docstrings.]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "def _dir(obj='__secret', _CLUTTER=dir()):\n",
    "    \"\"\"\n",
    "    A version of dir that excludes clutter and private names.\n",
    "    \"\"\"\n",
    "    if obj == '__secret':\n",
    "        names = globals().keys()\n",
    "    else:\n",
    "        names = dir(obj)\n",
    "    return [n for n in names if n not in _CLUTTER and not n.startswith('_')]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[]"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "_dir()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[]"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import csv\n",
    "_dir()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<module 'csv' from 'E:\\\\Anaconda3\\\\lib\\\\csv.py'>"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "csv"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "_dir(csv)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "csv.reader"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "csv.writer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "csv.spam"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "csv.spam = 'Python is dangerous'\n",
    "csv.spam"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "csv.reader = csv.writer\n",
    "csv.reader"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from csv import reader as csv_reader\n",
    "_dir()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "csv.reader is csv_reader"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "csv"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "csv.reader"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "del csv\n",
    "import csv as csv_module\n",
    "_dir()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "csv_module.reader is csv_reader"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "csv_module.reader"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "math"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "math + 3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "del math"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(math)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  Will the next statement give a `NameError` like the previous statement?  Why not?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import math"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "math"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "del math"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  What if we don't know the name of the module until run-time?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import importlib"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "importlib.import_module('math')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "math.pi"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "math_module = importlib.import_module('math')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "math.pi"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "math_module.pi"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "module_name = 'math'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import module_name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import 'math'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import math"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.3 Exercises: The `import` Statement"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  Explore reloading a module.  This is rarely needed and usually only when exploring."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  Several statements below will throw errors - try to figure out which ones before you run them."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import csv"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import importlib"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "importlib.reload?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "del csv"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "importlib.reload(csv)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "importlib.reload('csv')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import csv"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "importlib.reload('csv')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "importlib.reload(csv)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.4 Augmented Assignment Statements"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Bind two names to the `str` object `'abc'`, then from it create `'abcd'`\n",
    "and rebind (reassign) one of the names:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "string_1 = string_2 = 'abc'\n",
    "string_1 is string_2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "string_2 = string_2 + 'd'\n",
    "string_1 is string_2, string_1, string_2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  This reassigns the second name so it is bound to a new\n",
    "object.  This works similarly if we start with two names for one\n",
    "`list` object and then reassign one of the names."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "list_1 = list_2 = ['a', 'b', 'c']\n",
    "list_1 is list_2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "list_2 = list_2 + ['d']\n",
    "list_1 is list_2, list_1, list_2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  If for the `str` objects we instead use an *augmented assignment\n",
    "statement*, specifically *in-place add* `+=`, we get the same\n",
    "behaviour as earlier."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "string_1 = string_2 = 'abc'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "string_2 += 'd'\n",
    "string_1 is string_2, string_1, string_2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  However, for the `list` objects the behaviour changes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "list_1 = list_2 = ['a', 'b', 'c']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "list_2 += ['d']\n",
    "list_1 is list_2, list_1, list_2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  The `+=` in `foo += 1` is not just syntactic sugar for `foo = foo +\n",
    "1`.  The `+=` and other augmented assignment statements have their\n",
    "own bytecodes and methods."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  Notice BINARY_ADD vs. INPLACE_ADD.  The run-time types of the\n",
    "objects to which `name_1` and `name_2` are bound are irrelevant to the\n",
    "bytecode that gets produced."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import codeop, dis"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dis.dis(codeop.compile_command(\"name_1 = name_1 + name_2\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dis.dis(codeop.compile_command(\"name_1 += name_2\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "list_2 = ['a', 'b', 'c']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "list_2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  Notice that `__iadd__` returns a value"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "list_2.__iadd__(['d'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  and it also changes the list"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "list_2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "string_2.__iadd__('4')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "So what happens when `INPLACE_ADD` operates on the `str` object?\n",
    "\n",
    "If `INPLACE_ADD` doesn't find `__iadd__` it instead calls `__add__` and\n",
    "reassigns `string_2`, i.e. it falls back to `__add__`.\n",
    "\n",
    "https://docs.python.org/3/reference/datamodel.html#object.__iadd__:\n",
    "\n",
    "> These methods are called to implement the augmented arithmetic\n",
    "> assignments (+=, etc.). These methods should attempt to do the\n",
    "> operation in-place (modifying self) and return the result (which\n",
    "> could be, but does not have to be, self). If a specific method is\n",
    "> not defined, the augmented assignment falls back to the normal\n",
    "> methods.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  Here's similar behaviour with a tuple:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tuple_1 = (7,)\n",
    "tuple_1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tuple_1[0].__iadd__(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tuple_1[0] += 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tuple_1[0] = tuple_1[0] + 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tuple_1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  Here's surprising behaviour with a tuple:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tuple_2 = ([12, 13],)\n",
    "tuple_2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tuple_2[0] += [14]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  What value do we expect `tuple_2` to have?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tuple_2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  Let's simulate the steps to see why this behaviour makes sense."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "list_1 = [12, 13]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tuple_2 = (list_1,)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tuple_2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "temp = list_1.__iadd__([14])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "temp"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "temp == list_1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "temp is list_1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tuple_2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tuple_2[0] = temp"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  For later study:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dis.dis(codeop.compile_command(\"tuple_2 = ([12, 13],); tuple_2[0] += [14]\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dis.dis(codeop.compile_command(\"tuple_2 = ([12, 13],); temp = tuple_2[0].__iadd__([14]); tuple_2[0] = temp\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  For a similar explanation see \n",
    "https://docs.python.org/3/faq/programming.html#faq-augmented-assignment-tuple-error"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.5 Function Arguments are Passed by Name Binding"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  Can functions modify the arguments passed to them?\n",
    "\n",
    "  When a caller passes an argument to a function, the function starts\n",
    "  execution with a local name, the parameter from its signature, bound\n",
    "  to the argument object passed in."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def function_1(string_2):\n",
    "    print('A -->', string_2)\n",
    "    string_2 += ' blue'\n",
    "    print('B -->', string_2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "string_1 = 'red'\n",
    "string_1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "function_1(string_1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "string_1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  To see more clearly why `string_1` is still a name bound to `'red'`, consider\n",
    "this version which is functionally equivalent but has two changes\n",
    "highlighted in the comments:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def function_2(string_2):\n",
    "    print('A -->', string_2)\n",
    "    string_2 = string_2 + ' blue'  # Changed from +=\n",
    "    print('B -->', string_2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "function_2('red')  # Changed from string_1 to 'red'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "'red'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  In both cases the name `string_2` at the beginning of `function_1` and\n",
    "`function_2` was a name that was bound to the `str` object `'red'`,\n",
    "and in both the function-local name `string_2` was re-bound to\n",
    "the new `str` object `'red blue'`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  Let's try this with a `list`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def function_3(list_2):\n",
    "    print('A -->', list_2)\n",
    "    list_2 += ['blue']  # += with lists is shorthand for list.extend()\n",
    "    print('B -->', list_2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "list_1 = ['red']\n",
    "list_1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "function_3(list_1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "list_1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  In both cases parameter names are bound to arguments, and whether or\n",
    "not the function can or does change the object passed in depends on\n",
    "the object, not how it's passed to the function."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
